#ifndef _IBEAN_H
#define _IBEAN_H
#include <stdio.h>
#include <string>
#include <functional>
#include <vector>
#include <map>
#include "INode.h"
class IBean {
public:
    virtual ~IBean(){}   
    template<typename T>
    T* addComponent(const std::string &name)
    {
        auto i = _components.find(name);
        if (i == _components.end()) {
            std::string vv;
            vv.resize(sizeof(T) + 4);
          
            auto ii = _components.insert({name,vv});
            if (ii.second) {
                return new(&ii.first->second[0])T;
            }
            return NULL;
        } else {
            return static_cast<T*>((void*)&i->second[0]);
        }
    }
    std::string * getAlloc(const std::string &name) {
        auto i = _components.find(name);
        if (i == _components.end()) {
            std::string vv;
            auto ii = _components.insert({name,vv});
            if (ii.second) {
                return &ii.first->second;
            }
            return NULL;
        } else {
            return &i->second;
        }
    }
    char * getComponent(const std::string &name) {
        auto it = _components.find(name);
        if (it != _components.end()) {
            return &it->second[0];
        }
        return NULL;
    }
private:
    std::map<std::string,std::string> _components;
};
class IBeanFactory {
public:
    virtual IBean *getIBean(const char*name) = 0;    
    virtual void addIBean(const char*name,IBean *bean) = 0;
};

template<typename IMP>
class BeanFactory : public IBeanFactory {
public:
    static BeanFactory &getInstance()   {
        static BeanFactory bf;
        return bf;
    }
    virtual IBean *getIBean(const char*name) {
        return getBean(name);
    }
    virtual void addIBean(const char*name,IBean *bean) 
    {
        addBean(name,(IMP*) bean);
    }
    IMP *getBean(const char *name) {
        auto iter = imps.find(name);
        if (iter != imps.end())
        {
           // printf("getBean %s %p %p\n",name,this,iter->second);
            return iter->second;
        }
       // printf("getBean %s %p null\n",name,this);
        return NULL;
    }

    void addBean(const char *name, IMP* imp)
    {
        imps[name] = imp;
       // printf("addBean %s %p %p\n",name,this,imp);
    }

    std::map<std::string, IMP*> imps;
};

class BeanFactoryManager {
public:
    static BeanFactoryManager &getInstance()   {
        static BeanFactoryManager bfm;
        return bfm;
    }
    void init();
    IBeanFactory *getFactory(const char *name);
    std::map<std::string, IBeanFactory *> factories;
};

template<typename IMP>
class Bean {
public:
    IMP* operator->() {
        return imps[name];
    }
    IMP *pointer(){
         return imps[name];
    }
    static std::map<std::string,IMP*> imps;
    Bean(const char *name)
    {
        auto i = imps.find(name);
        if ( i == imps.end())
        {
            imps[name] = BeanFactory<IMP>::getInstance().getBean(name);
        }
        this->name = name;
    }
    Bean()
    {
        auto i = imps.find("default");
        if ( i == imps.end())
        {
            imps["default"] = BeanFactory<IMP>::getInstance().getBean("default");
        }
        this->name = "default";
    }
    std::string name;
};
template<typename IMP>
std::map<std::string,IMP*> Bean<IMP>::imps;


#define ADD_INTERFACE(INTER)\
    factories[#INTER] = &BeanFactory<INTER>::getInstance();
#endif // _IBEAN_H